package com.oromwin.repos.client;

import java.io.*; 
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;

import com.oromwin.repos.common.Logger;
import com.oromwin.repos.common.ReposException;
import com.oromwin.repos.data.MediaTable;
import com.oromwin.repos.data.VolumeTable;

public class ReposAdminClient {
    private static Log log = Logger.getLog(ReposAdminClient.class);
    private static final String HORIZONTAL_BAR = "===============================================================================================================";
    private static final String PACKAGE_NAME = "Document Repository Admin Client";
    private static final double VERSION = 1.0; 

    private static final String CONST_QUIT = "quit";
    private static final String CONST_TOP = "top";

    private static final int CONST_DEFAULT_PROMPT = 0;

    private static final int CONST_VOLUME_MANAGER = 1;
    private static final int CONST_CREATE_VOLUME = 11;
    private static final int CONST_DELETE_VOLUME = 12;
    private static final int CONST_INFO_VOLUME = 13;
    private static final int CONST_LIST_VOLUME = 14;

    private static final int CONST_MEDIA_MANAGER = 2;
    private static final int CONST_CREATE_MEDIA = 21;
    private static final int CONST_UPDATE_MEDIA = 22;
    private static final int CONST_DELETE_MEDIA = 24;
    private static final int CONST_INFO_MEDIA = 25;

    private static ReposSocketClient client = null;
    private static Map volumeMap = new HashMap();
    private static Map mediaMap = new HashMap();

    public void printHeader() {
        System.out.println("");
        System.out.println(HORIZONTAL_BAR);
        System.out.println("\t" + PACKAGE_NAME + ", v" + VERSION);
    }

    public void printTail(String message) {
        System.out.println("Status:\t" + message);
        System.out.println(HORIZONTAL_BAR);
        System.out.println("");
    }

    public void printMenu(int number) throws ReposException {
        if (number == CONST_DEFAULT_PROMPT) {
            System.out.println("[1]\t Volume Management");
            System.out.println("[2]\t Media Management");
            System.out.println("");
            System.out.println("[" + CONST_QUIT + "]\t Quit");

        } else if (number == CONST_VOLUME_MANAGER) {
            System.out.println("[1]\t Create Volume");
            System.out.println("[2]\t Delete Volume");
            System.out.println("[3]\t Info Volume");
            System.out.println("[4]\t List Volume");
            System.out.println("");
            System.out.println("[" + CONST_TOP + "]\t Top");

        } else if (number == CONST_CREATE_VOLUME || number == CONST_DELETE_VOLUME || number == CONST_INFO_VOLUME || number == CONST_LIST_VOLUME ||
                number == CONST_CREATE_MEDIA || number == CONST_UPDATE_MEDIA || number == CONST_DELETE_MEDIA || number == CONST_INFO_MEDIA) {
            volumeMap.clear();
            List volumeList = client.listRepository();
            Iterator iterator = volumeList.iterator();
            int index = 0;
            while (iterator.hasNext()) {
                index++;
                Object object = iterator.next();
                Integer key = new Integer(index);
                if (object instanceof VolumeTable) {
                    VolumeTable volumeTable = (VolumeTable) object;
                    String value = volumeTable.getVolumeId();
                    volumeMap.put(key, value);
                    System.out.println("[" + index + "] " + volumeTable.getVolumeName()+ " : " + value);
                } else {
                    System.out.println("[" + index + "] " + "Casting exception: Insufficient VolumeTable object instance, " + object.getClass().toString());
                }
            }

        } else if (number == CONST_MEDIA_MANAGER) {
            System.out.println("[1]\t Create Media");
            System.out.println("[2]\t Update Media");
            System.out.println("[3]\t Delete Media");
            System.out.println("[4]\t Info Media");
            System.out.println("");
            System.out.println("[" + CONST_TOP + "]\t Top");

        }
    }

    public String promptString(BufferedReader stdin, String message) throws IOException, ReposException {
        System.out.print(message);
        System.out.flush();
        String input = stdin.readLine().trim();
        if (input.length() == 0) {
            throw ReposException.create(log, "Illegal input value [" + input + "]");
        } else {
            return input;
        }
    }

    public Integer promptInteger(BufferedReader stdin, String message) throws IOException, ReposException {
        System.out.print(message);
        System.out.flush();
        String input = stdin.readLine().trim();
        if (input.length() == 0) {
            throw ReposException.create(log, "Illegal input value [" + input + "]");
        } else {
            return new Integer(Integer.parseInt(input));
        }
    }

    public Long promptLong(BufferedReader stdin, String message) throws IOException, ReposException {
        System.out.print(message);
        System.out.flush();
        String input = stdin.readLine().trim();
        if (input.length() == 0) {
            throw ReposException.create(log, "Illegal input value [" + input + "]");
        } else {
            return new Long(Long.parseLong(input));
        }
    }

    public void printExit() {
        System.out.println("Exit program");
    }

    public static void main(String[] args) {

        String _hostname = "localhost";
        int _port = 5000;
        
        try {
            if (args.length == 0) {
                System.out.println("Use default hostname[" + _hostname + "] and port[" + _port + "]");
            } else if (args.length == 1) {
                _hostname = args[0];
                System.out.println("Use input hostname[" + _hostname + "] and default port[" + _port + "]");
            } else if (args.length == 2) {
                _hostname = args[0];
                _port = Integer.parseInt(args[1]);
                System.out.println("Use input hostname[" + _hostname + "] and port[" + _port + "]");
            } else if (args.length > 2) {
                System.out.println("Illeagl arguments length, Exit program now.");
                System.exit(0);
            }
            client = new ReposSocketClient(_hostname, _port);
            
        } catch (IllegalArgumentException e) {
            System.out.println("Illegal Arguements - " + e.getMessage());
            e.printStackTrace();
            
        }

        ReposAdminClient admin = new ReposAdminClient();
        BufferedReader stdin = new BufferedReader(new InputStreamReader (System.in));
        int count = 1;
        String history = "";
        int menuNumber = 0;
        String status = "";

        while (count > 0) {
            try {
                admin.printHeader();
                admin.printMenu(menuNumber);
                admin.printTail(status);
                history += admin.promptString(stdin, "Enter a number of menu (number or " + CONST_QUIT + "): ");
                
                if (history.endsWith(CONST_QUIT)) {
                    break;

                } else if (history.endsWith(CONST_TOP)) {
                    history = "";
                    menuNumber = CONST_DEFAULT_PROMPT;
                    status = "Back to Top Menu";

                } else if (history.startsWith("1")) {
                    if (history.compareTo("1") == 0) {
                        menuNumber = CONST_VOLUME_MANAGER;
                        status = "Volume Management";

                    } else if (history.compareTo("11") == 0) {
                        String volumeName = admin.promptString(stdin, "Type Volume Name: ");
                        client.createVolume(volumeName);
                        history = "1";
                        menuNumber = CONST_VOLUME_MANAGER;
                        status = "Volume '" + volumeName + "' was Created";

                    } else if (history.startsWith("12")) {
                        admin.printMenu(CONST_DELETE_VOLUME);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        String response = admin.promptString(stdin, "Really delete Volume [" + volumeId + "] and Media permanently ? [yes|no]: ");
                        if (response.compareTo("yes") == 0) {
                            client.deleteVolume(volumeId, true);
                            System.out.println("Volume [" + volumeId + "] has Deleted permanently");
                        } else {
                            System.out.println("Delete Volume Canceled");
                        }
                        history = "1";
                        menuNumber = CONST_VOLUME_MANAGER;
                        status = "Volume '" + volumeId + "' was Deleted";

                    } else if (history.startsWith("13")) {
                        admin.printMenu(CONST_INFO_VOLUME);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        VolumeTable volumeTable = client.infoVolume(volumeId);
                        System.out.println(volumeTable.toString());
                        history = "1";
                        menuNumber = CONST_VOLUME_MANAGER;
                        status = "Information about Volume [ " + volumeId + " ]";

                    } else if (history.startsWith("14")) {
                        admin.printMenu(CONST_LIST_VOLUME);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        List mediaList = client.listVolume(volumeId);
                        Iterator iterator = mediaList.iterator();
                        int index = 0;
                        while (iterator.hasNext()) {
                            index++;
                            Object object = iterator.next();
                            if (object instanceof MediaTable) {
                                MediaTable mediaTable = (MediaTable) object;
                                System.out.println("[" + index + "] " + mediaTable.getMediaId() + " : " + mediaTable.getMediaPath() + ", " + mediaTable.getMediaUsedBytes() + " bytes Used, " + mediaTable.getMediaFreeBytes() + " bytes Available");
                            } else {
                                System.out.println("[" + index + "] Casting exception: Insufficient MediaTable object instance, " + object.getClass().toString());
                            }
                        }
                        history = "1";
                        menuNumber = CONST_VOLUME_MANAGER;
                        status = "Media Information about Volume [ " + volumeId + " ]";

                    }

                } else if (history.startsWith("2")) {
                    if (history.compareTo("2") == 0) {
                        menuNumber = CONST_MEDIA_MANAGER;
                        status = "Media Management";

                    } else if (history.compareTo("21") == 0) {
                        admin.printMenu(CONST_CREATE_MEDIA);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        File mediaPath = new File(admin.promptString(stdin, "Type MediaPath: "));
                        Long mediaMaxBytes = admin.promptLong(stdin, "Type MediaMaxBytes: ");
                        String mediaId = client.createMedia(volumeId, mediaPath, mediaMaxBytes.longValue());
                        history = "2";
                        menuNumber = CONST_MEDIA_MANAGER;
                        status = "Media '" + mediaId + "' was Created";

                    } else if (history.compareTo("22") == 0) {
                        admin.printMenu(CONST_UPDATE_MEDIA);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        List mediaList = client.listVolume(volumeId);
                        mediaMap.clear();
                        Iterator iterator = mediaList.iterator();
                        int index = 0;
                        while (iterator.hasNext()) {
                            index++;
                            Object object = iterator.next();
                            Integer key = new Integer(index);
                            if (object instanceof MediaTable) {
                                MediaTable mediaTable = (MediaTable) object;
                                String value = mediaTable.getMediaId(); 
                                mediaMap.put(key, value);
                                System.out.println("[" + index + "] " + mediaTable.getMediaId() + " : " + mediaTable.getMediaPath() + ", " + mediaTable.getMediaUsedBytes() + " bytes Used, " + mediaTable.getMediaFreeBytes() + " bytes Available");
                            } else {
                                System.out.println("[" + index + "] Casting exception: Insufficient MediaTable object instance, " + object.getClass().toString());
                            }
                        }
                        Integer mediaIndex = admin.promptInteger(stdin, "Select Media Number: ");
                        String mediaId = (String) mediaMap.get(mediaIndex);
                        Long mediaMaxBytes = admin.promptLong(stdin, "Type MediaMaxBytes: ");
                        client.updateMedia(mediaId, mediaMaxBytes.longValue());
                        history = "2";
                        menuNumber = CONST_MEDIA_MANAGER;
                        status = "Media '" + mediaId + "' was Updated";

                    } else if (history.compareTo("23") == 0) {
                        admin.printMenu(CONST_DELETE_MEDIA);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        List mediaList = client.listVolume(volumeId);
                        mediaMap.clear();
                        Iterator iterator = mediaList.iterator();
                        int index = 0;
                        while (iterator.hasNext()) {
                            index++;
                            Object object = iterator.next();
                            Integer key = new Integer(index);
                            if (object instanceof MediaTable) {
                                MediaTable mediaTable = (MediaTable) object;
                                String value = mediaTable.getMediaId(); 
                                mediaMap.put(key, value);
                                System.out.println("[" + index + "] " + mediaTable.getMediaId() + " : " + mediaTable.getMediaPath() + ", " + mediaTable.getMediaUsedBytes() + " bytes Used, " + mediaTable.getMediaFreeBytes() + " bytes Available");
                            } else {
                                System.out.println("[" + index + "] Casting exception: Insufficient MediaTable object instance, " + object.getClass().toString());
                            }
                        }
                        Integer mediaIndex = admin.promptInteger(stdin, "Select Media Number: ");
                        String mediaId = (String) mediaMap.get(mediaIndex);
                        String response = admin.promptString(stdin, "Really delete Media [" + mediaId + "] permanently ? [yes|no]: ");
                        if (response.compareTo("yes") == 0) {
                            client.deleteMedia(mediaId, true);
                            System.out.println("Media [" + mediaId + "] has Deleted permanently");
                        } else {
                            System.out.println("Delete Media Canceled");
                        }
                        history = "2";
                        menuNumber = CONST_MEDIA_MANAGER;
                        status = "Media '" + mediaId + "' was Deleted";

                    } else if (history.compareTo("24") == 0) {
                        admin.printMenu(CONST_INFO_MEDIA);
                        Integer volumeIndex = admin.promptInteger(stdin, "Select Volume Number: ");
                        String volumeId = (String) volumeMap.get(volumeIndex);
                        List mediaList = client.listVolume(volumeId);
                        mediaMap.clear();
                        Iterator iterator = mediaList.iterator();
                        int index = 0;
                        while (iterator.hasNext()) {
                            index++;
                            Object object = iterator.next();
                            Integer key = new Integer(index);
                            if (object instanceof MediaTable) {
                                MediaTable mediaTable = (MediaTable) object;
                                String value = mediaTable.getMediaId(); 
                                mediaMap.put(key, value);
                                System.out.println("[" + index + "] " + mediaTable.getMediaId() + " : " + mediaTable.getMediaPath() + ", " + mediaTable.getMediaUsedBytes() + " bytes Used, " + mediaTable.getMediaFreeBytes() + " bytes Available");
                            } else {
                                System.out.println("[" + index + "] Casting exception: Insufficient MediaTable object instance, " + object.getClass().toString());
                            }
                        }
                        Integer mediaIndex = admin.promptInteger(stdin, "Select Media Number: ");
                        String mediaId = (String) mediaMap.get(mediaIndex);
                        MediaTable mediaTable = client.infoMedia(mediaId);
                        System.out.println(mediaTable.toString());
                        history = "2";
                        menuNumber = CONST_MEDIA_MANAGER;
                        status = "Information about Media '" + mediaId + "' ";

                    }

                } else {
                    status = "Illegal Input Value";
                    continue;

                }
                
            } catch (IOException e) {
                history = "";
                menuNumber = CONST_DEFAULT_PROMPT;
                status = "Illegal User Input Values - " + e.getMessage();

            } catch (SecurityException e) {
                history = "";
                menuNumber = CONST_DEFAULT_PROMPT;
                status = "Can't Access to Socket Server with Security Problem - " + e.getMessage();

            } catch (ReposException e) {
                history = "";
                menuNumber = CONST_DEFAULT_PROMPT;
                status = "Failed to current action - " + e.getMessage();

            } catch (Exception e) {
                e.printStackTrace();
                history = "";
                menuNumber = CONST_DEFAULT_PROMPT;
                status = "Unexpected exception exit program now";
                break;

            }
            count += 1;
        }
        admin.printExit();
    }

}